package com.joshjung.echosurf.test
{
    import com.joshjung.echosurf.ESSocket;
    import com.joshjung.echosurf.event.ESCAuthenticateEvent;
    import com.joshjung.echosurf.event.ESLeaveEvent;
    import com.joshjung.echosurf.event.ESServerEvent;

    import flash.events.Event;
    import flash.net.Socket;
    import flash.utils.setTimeout;

    import flexunit.framework.Assert;

    import org.flexunit.asserts.assertEquals;
    import org.flexunit.asserts.assertFalse;
    import org.flexunit.asserts.assertTrue;
    import org.flexunit.async.Async;

    /**
     * This class tests the echoSurf server to make sure it is working properly.
     *
     * @author jjung
     */
    public class EchoSurfTest
    {
        public var socket1 : ESSocket = null;
        public var socket2 : ESSocket = null;

        [Before]
        public function setUp() : void
        {
            socket1 = new ESSocket("50.56.122.53", 1002, 0);
            socket2 = new ESSocket("50.56.122.53", 1002, 0);
        }

        [After]
        public function tearDown() : void
        {

        }

        public function waitBetweenTests() : void
        {
            // Close our connections
            if (socket1)
            {
                socket1.close();
            }

            if (socket2)
            {
                socket2.close();
            }

            setTimeout(Async.asyncHandler(this, successTimeout, 10000, null, null), 2000);
        }

        //-----------------------------
        //  CONNECT - 1 CLIENT
        //-----------------------------
        [Test(async, description = "Connects one client to the server and verifies that the connection is made.", order = 1)]
        public function connectToServer_oneClient() : void
        {
            socket1.addEventListener(ESCAuthenticateEvent.AUTHENTICATE, Async.asyncHandler(this, connectToServer_oneClient_SUCCESS, 10000, null, failHandler));
            socket1.connect();
        }

        protected function connectToServer_oneClient_SUCCESS(event : Event, passThroughData : *) : void
        {
            assertEquals(socket1.connected, true);
            assertEquals(socket1.clientID, 1);
            assertEquals(socket1.serverID, 1);
            assertEquals(socket1.isServer, true);

            waitBetweenTests();
        }

        //-----------------------------
        //  CONNECT - 2 CLIENT
        //-----------------------------
        [Test(async, description = "Connects two clients to the server and then kills the peer and waits for the message.", order = 2)]
        public function connectToServer_multipleClient() : void
        {
            socket1.addEventListener(ESCAuthenticateEvent.AUTHENTICATE, Async.asyncHandler(this, connectToServer_socket1Connect, 10000, null, failHandler));
            socket1.connect();
        }

        protected function connectToServer_socket1Connect(event : Event, passThroughData : *) : void
        {
            // Socket 1 has connected
            assertEquals(socket1.clientID, 1);
            assertEquals(socket1.serverID, 1);
            assertEquals(socket1.isServer, true);

            // Now connect socket 2
            socket2.addEventListener(ESCAuthenticateEvent.AUTHENTICATE, Async.asyncHandler(this, connectToServer_socket2Connect, 10000, null, failHandler));
            socket2.connect();
        }

        protected function connectToServer_socket2Connect(event : Event, passThroughData : *) : void
        {
            assertEquals(socket2.clientID, 2);
            assertEquals(socket2.serverID, 1);
            assertEquals(socket2.isServer, false);

            socket1.addEventListener(ESLeaveEvent.PEER_LEAVE, Async.asyncHandler(this, connectToServer_peerLeave, 10000, null, failHandler));
            socket2.close();
        }

        protected function connectToServer_peerLeave(event : ESLeaveEvent, passThroughData : *) : void
        {
            assertEquals(event.clientID, 2);
            
            waitBetweenTests();
        }

        //-----------------------------
        //  CONNECT - 2 CLIENT SERVER DIES
        //-----------------------------
        [Test(async, description = "Connects two clients to the server and then kills the server and waits for server control to pass to the other one.", order = 3)]
        public function connectToServer_multipleClientServerDies() : void
        {
            socket1.addEventListener(ESCAuthenticateEvent.AUTHENTICATE, Async.asyncHandler(this, connectToServer_socket1Connect2, 10000, null, failHandler));
            socket1.connect();
        }

        protected function connectToServer_socket1Connect2(event : Event, passThroughData : *) : void
        {
            assertTrue(socket1.isServer);

            socket2.addEventListener(ESCAuthenticateEvent.AUTHENTICATE, Async.asyncHandler(this, connectToServer_socket2Connect2, 10000, null, failHandler));
            socket2.connect();
        }

        protected function connectToServer_socket2Connect2(event : Event, passThroughData : *) : void
        {
            assertFalse(socket2.isServer);

            socket2.addEventListener(ESServerEvent.START_SERVING, Async.asyncHandler(this, _startServing, 10000, null, failHandler));
            socket1.close();
        }

        protected function _startServing(event : ESServerEvent, passThroughData : *) : void
        {
            assertEquals(socket2.isServer, true);
        }

        //---------------------------------------------------------------------
        //
        //  Events
        //
        //---------------------------------------------------------------------
        protected function failHandler(event : Event) : void
        {
            Assert.fail("A failure occurred running a test.");
        }

        protected function successTimeout(event : Event, passThroughData : *) : void
        {

        }
    }
}
